#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2018/12/11 0:01
# @Author  : lizhen
# @Site    : 
# @File    : cPandas.py
# @Software: PyCharm
import numpy as np
import pandas as pd
from pandas import Series, DataFrame
import matplotlib.pyplot as plt


class PandasDemo:
    def __init__(self):
        self.ser = Series()
        self.df = DataFrame()

    def _test_series_create(self):
        """
        pdm = PandasDemo()
        pdm._test_series_create()
        """
        ser = Series(np.arange(1, 11), index=np.arange(10))  # 一维数组, 字典可以直接转化为series
        self.ser = ser
        print(ser, ser.values, ser.index)
        print(ser.reindex(np.arange(5, 10), fill_value=0))  # 数组的值、数组的索引、重新定义索引
        print(ser.isnull(), pd.isnull(ser), pd.notnull(ser))  # 检测缺失数据
        ser.name = 'ser_name'
        ser.index.name = 'ser_index_name'  # ser本身的名字、ser索引的名字
        print(ser)
        print(ser.drop(0))  # 丢弃索引x对应的值
        print(ser + ser)  # 算术运算
        print(ser.sort_index())
        print(ser.sort_values())  # 按索引排序、按值排序

    def _test_dataframe_create(self):
        """
        pdm = PandasDemo()
        pdm._test_dataframe_create()
        """
        data = {'name': ['Peter', 'Daniel', 'Marry', 'Lily'], 'age': [15, 25, 18, 30], 'gender': ['f', 'm', 'f', 'f']}
        df = DataFrame(data, columns=['name', 'gender', 'age'], index=range(1, 5))  # 表结构的数据结构，既有行索引又有列索引
        self.df = df
        print(df)
        print(df.ix[1])  # 索引为x的值    对于series，直接使用ser['x']
        del df['gender']  # 用del删除第ly列
        print(df)
        print(df.T, df.index.name, df.columns.name, df.values, df.drop([1]), df + df)
        print(df.add(df))  # 算术运算
        f = lambda x: x.max() - x.min()
        df = pd.DataFrame(np.arange(10))
        print(df.apply(f, axis=1))
        print(df.sort_index(axis=1, ascending=False))  # 按行索引排序
        print(df.sort_index(by=[0, 1]))  # 按a、b列索引排序
        ser = self.ser
        print(ser.rank())
        print(df.rank(axis=1))  # 排序，增设一个排名值
        print(df.sum())
        print(df.sum(axis=1))  # 按列、按行求和
        print(df.mean(axis=1, skipna=False))  # 求各行的平均值，考虑na的存在
        print(df.idxmax())  # 返回最大值的索引
        print(df.cumsum())  # 累计求和
        print(df.describe())
        print(ser.describe())  # 返回count mean std min max等值
        print(ser.unique())  # 去重
        print(ser.value_counts())  # 返回一个series，其索引为唯一值，值为频率
        print(ser.isin([1, 2]))  # 判断ser的值是否为x,y，得到布尔值
        print(ser.dropna())
        print(ser.isnull())
        print(ser.notnull())
        print(ser.fillna(0))  # 处理缺失数据，df相同
        print(df.unstack())  # 行列索引和值互换  df.unstack().stack()
        # print(df.swaplevel('key1', 'key2'))  # 接受两个级别编号或名称，并互换
        # df.sortlevel(1)  # 根据级别1进行排序，df的行、列索引可以有两级
        # df.set_index(['name', 'age'], drop=False)  # 将c、d两列转换为行,因drop为false，在列中仍保留c,d
        # read_csv
        # read_table
        # read_fwf  # 读取文件分隔符为逗号、分隔符为制表符('\t')、无分隔符（固定列宽）
        # pd.read_csv('...', nrows=5)  # 读取文件前5行
        # pd.read_csv('...', chunksize=1000)  # 按块读取，避免过大的文件占用内存
        # pd.load()  # pd也有load方法，用来读取二进制文件
        # pd.ExcelFile('...xls').parse('Sheet1')  # 读取excel文件中的sheet1
        # df.to_csv('...csv', sep='|', index=False, header=False)  # 将数据写入csv文件，以｜为分隔符，默认以，为分隔符, 禁用列、行的标签
        # pd.merge(df1, df2, on='key', suffixes=(
        # '_left', '_right'))  # 合并两个数据集,类似数据库的inner join, 以二者共有的key列作为键,suffixes将两个key分别命名为key_left、key_right
        # pd.merge(df1, df2, left_on='lkey', right_on='rkey')  # 合并，类似数据库的inner join, 但二者没有同样的列名，分别指出，作为合并的参照
        # pd.merge(df1, df2, how='outer')  # 合并，但是是outer join；how='left'是笛卡尔积，how='inner'是...;还可以对多个键进行合并
        # df1.join(df2, on='key', how='outer')  # 也是合并
        # pd.concat([ser1, ser2, ser3], axis=1)  # 连接三个序列，按行的方向
        # ser1.combine_first(ser2)
        # df1.combine_first(df2)  # 把2合并到1上，并对齐
        # df.stack()
        # df.unstack()  # 列旋转为行、行旋转为列
        # df.pivot()
        # df.duplicated()
        # df.drop_duplicates()  # 判断是否为重复数据、删除重复数据
        # df[''].map(lambda x: abs(x))  # 将函数映射到df的指定列
        # ser.replace(-999, np.nan)  # 将－999全部替换为nan
        # df.rename(index={}, columns={}, inplace=True)  # 修改索引，inplace为真表示就地修改数据集
        # pd.cut(ser, bins)  # 根据面元bin判断ser的各个数据属于哪一个区段，有labels、levels属性
        # df[(np.abs(df) > 3).any(1)]  # 输出含有“超过3或－3的值”的行
        # permutation
        # take  # 用来进行随机重排序
        # pd.get_dummies(df['key'], prefix='key')  # 给df的所有列索引加前缀key
        # df[...].str.contains()
        # df[...].str.findall(pattern, flags=re.IGNORECASE)
        # df[...].str.match(pattern, flags=...)
        # df[...].str.get()  # 矢量化的字符串函数

    def _test_plot(self):
        """
        pdm = PandasDemo()
        pdm._test_plot()
        """
        self.ser = Series(np.arange(1, 11), index=np.arange(10))
        ser = self.ser
        ser.plot()
        plt.show()

        data = {'name': ['Peter', 'Daniel', 'Marry', 'Lily'], 'age': [15, 25, 18, 30], 'gender': ['f', 'm', 'f', 'f']}
        self.df = DataFrame(data, columns=['name', 'gender', 'age'], index=range(1, 5))  # 表结构的数据结构，既有行索引又有列索引
        df = self.df
        df.plot()  # pandas的绘图工具，有参数label, ax, style, alpha, kind, logy, use_index, rot, xticks, xlim, grid等，详见page257
        plt.show()

        # kind = 'kde'  # 密度图
        # kind = 'bar'
        # kind = 'barh'  # 垂直柱状图、水平柱状图，stacked=True为堆积图
        ser.hist(bins=50)  # 直方图
        plt.show()

        plt.scatter(np.arange(1, 5)[0:2], np.arange(1, 10, 3)[0:2])  # 绘制x,y组成的散点图
        plt.show()

        pd.plotting.scatter_matrix(df, diagonal='kde', color='k', alpha='0.3')  # 将df各列分别组合绘制散点图
        plt.show()

    def _test_aggregate(self):
        """
        pdm = PandasDemo()
        pdm._test_aggregate()
        """
        data = {'name': ['Peter', 'Daniel', 'Marry', 'Lily'], 'age': [15, 25, 18, 30], 'gender': ['f', 'm', 'f', 'f']}
        self.df = DataFrame(data, columns=['name', 'gender', 'age'], index=range(1, 5))  # 表结构的数据结构，既有行索引又有列索引
        df = self.df
        # 默认在axis = 0
        # 轴上分组，也可以在1组上分组；可以用for进行分组迭代
        df.groupby(df['name'])  # 根据key1对df进行分组
        # df['key2'].groupby(df['key1'])  # 根据key1对key2列进行分组
        # df['key3'].groupby(df['key1'], df['key2'])  # 先根据key1、再根据key2对key3列进行分组
        # df['key2'].groupby(df['key1']).size()  # size()返回一个含有分组大小的series
        # df.groupby(df['key1'])['data1']
        # 等价于
        # df['data1'].groupby(df['key1'])
        # df.groupby(df['key1'])[['data1']]
        # 等价于
        # df[['data1']].groupby(df['key1'])
        # df.groupby(mapping, axis=1)
        # ser(mapping)  # 定义mapping字典，根据字典的分组来进行分组
        # df.groupby(len)  # 通过函数来进行分组，如根据len函数
        # df.groupby(level='...', axis=1)  # 根据索引级别来分组
        # df.groupby([], as_index=False)  # 禁用索引，返回无索引形式的数据
        # df.groupby(...).agg(['mean', 'std'])  # 一次使用多个聚合函数时，用agg方法
        # df.groupby(...).transform(np.mean)  # transform()可以将其内的函数用于各个分组
        # df.groupby().apply()  # apply方法会将待处理的对象拆分成多个片段，然后对各片段调用传入的函数，最后尝试将各片段组合到一起

    def _test_perspect(self):
        """
        pdm = PandasDemo()
        pdm._test_perspect()
        """
        data = {'name': ['Peter', 'Daniel', 'Marry', 'Lily'], 'age': [15, 25, 18, 30], 'gender': ['f', 'm', 'f', 'f']}
        self.df = DataFrame(data, columns=['name', 'gender', 'age'], index=range(1, 5))  # 表结构的数据结构，既有行索引又有列索引
        df = self.df
        # df.pivot_table(['', ''], rows=['', ''], cols='', margins=True)  # margins为真时会加一列all
        pd.crosstab(df.name, df.age, margins=True)  # margins作用同上

    def _test_sequence_create(self):
        """
        pdm = PandasDemo()
        pdm._test_sequence_create()
        """
        print(pd.to_datetime('20181211230122'))  # 将字符串型日期解析为日期格式
        print(pd.date_range('1/1/2000', periods=1000))  # 生成时间序列
        # ts.resample('D', how='mean')  # 采样，将时间序列转换成以每天为固定频率的, 并计算均值；how='ohlc'是股票四个指数；
        # ＃重采样会聚合，即将短频率（日）变成长频率（月），对应的值叠加；
        # ＃升采样会插值，即将长频率变为短频率，中间产生新值
        # ts.shift(2, freq='D')
        # ts.shift(-2, freq='D')  # 后移、前移2天
        # now + Day()
        # now + MonthEnd()
        # import pytz
        # pytz.timezone('US/Eastern')  # 时区操作，需要安装pytz
        # pd.Period('2010', freq='A-DEC')   ＃period表示时间区间，叫做时期
        # pd.PeriodIndex  # 时期索引
        # ts.to_period('M')  # 时间转换为时期
        # pd.rolling_mean(...)
        # pd.rolling_std(...)  # 移动窗口函数－平均值、标准差


if __name__ == '__main__':
    pdm = PandasDemo()
    pdm._test_sequence_create()
